﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Factory</title>
    <script src="../../resource/lib/jquery-1.10.2.js"></script>
    <script src="../../resource/lib/d3.js"></script>
    <script src="angular.1.2.0.min.js"></script>
    <script src="util.js"></script>
</head>
<body ng-app='svg'>
    <svg-html></svg-html>
</body>
</html>
<script>
    var app = angular.module("svg", [], function () { });

    app.factory("Diagram", [function () {
        var Diagram = function (domEl) {
            this.readOnlySvgD3Object = domEl;
            this._domEl = domEl;
            var that = this;

            this._elementList = [];
            this._selectedElement = null;
            this._selectedOffset = null;
            this.addElement = function (el) {
                this._elementList.push(el);
                el.updateLayout();
            }

            this._domEl.on("mousedown", function () {
                var mousePos = { x: d3.event.x, y: d3.event.y };
                for (var i = that._elementList.length - 1; i >= 0; i--) {
                    if (that._elementList[i].hitTest != undefined) {
                        var hitResult = that._elementList[i].hitTest(mousePos);
                        if (hitResult.isHit) {
                            that._selectedElement = that._elementList[i];
                            that._selectedOffset = { x: hitResult.offsetX, y: hitResult.offsetY };
                            break;
                        }
                    }
                }
            })

            this._domEl.on("mousemove", function () {
                if (that._selectedElement != null) {
                    var mousePos = { x: d3.event.x + that._selectedOffset.x, y: d3.event.y + that._selectedOffset.y };
                    that._selectedElement.setActualPosition(mousePos);
                    that._selectedElement.updateLayout();
                }
            })

            this._domEl.on("mouseup", function () { that._selectedElement = null; })
        }
        return Diagram;
    }]);

    app.factory("Element", [function () {
        var Element = function () {
            this.updateLayout = function () { }
            this.getDomEl = function () { }
            this.getPosition = function () { };
            this.getSize = function () { };
            this.setPosition = function (pos) { };
            this.setSize = function (size) { };
            this.logFlag = true;

            this.hide = function () {
                this._domEl.attr("display", "none");
            }
        }
        return Element;
    }]);

    app.factory("BaseNode", ["Element", function (Element) {
        var BaseNode = function (domEl, position, size) {
            this._domEl = domEl;
            Element.apply(this, []);

            this._position = position;
            this._size = size;
            this._parent = null;

            this.getDomEl = function () {
                return this._domEl;
            }

            this._linkList = new Array();

            this.addLink = function (link) {
                this._linkList.push(link);
            }

            this.setPosition = function (pos) {
                this._position = pos;
            }

            this.setSize = function (size) {
                this._size = size;
            }

            this.getSize = function () {
                return this._size;
            }

            this.updateLayout = function () {
                this.onUpdateLayout();
                for (var i = 0; i < this._linkList.length; i++) {
                    this._linkList[i].updateLayout();
                }
            }

            this.onUpdateLayout = function () { };
            this.hitTest = function (pos) { };
            this.getActualPosition = function () {
                var pos = { x: parseInt(this._position.x), y: parseInt(this._position.y) };
                var parent = this._parent;
                while (parent != null) {
                    pos.x += parseInt(parent._position.x);
                    pos.y += parseInt(parent._position.y);
                    parent = parent._parent;
                }
                return pos;
            }
            this.setActualPosition = function (actualPos) {
                var parent = this._parent;
                if (parent == null) {
                    this._position = actualPos;
                }
                else {
                    var pactual = this._parent.getActualPosition();
                    if (actualPos.x >= pactual.x
                        && actualPos.x + this._size.w <= pactual.x + this._parent.getSize().w
                        && actualPos.y >= pactual.y
                        && actualPos.y + this._size.h <= pactual.y + this._parent.getSize().h) {
                        var pos = { x: actualPos.x, y: actualPos.y };
                        while (parent != null) {
                            pos.x -= parent._position.x;
                            pos.y -= parent._position.y;
                            parent = parent._parent;
                        }

                        this._position.x = pos.x;
                        this._position.y = pos.y;
                    }
                }
            }
        }
        return BaseNode;
    }]);

    app.factory("BaseLine", ["BaseNode", function (BaseNode) {
        var BaseLine = function (domEl) {
            BaseNode.apply(this, [domEl, null, null]);
            this.getActualPosition = function () {

                var pos = { x: parseInt(this._position.x), y: parseInt(this._position.y) };
                var parent = this._parent;
                while (parent != null) {
                    pos.x += parseInt(parent._position.x);
                    pos.y += parseInt(parent._position.y);
                    parent = parent._parent;
                }
                return pos;
            }
            this.setActualPosition = function (actualPos) {
                var parent = this._parent;
                if (parent == null) {
                    this._position = actualPos;
                }
                else {
                    var pactual = this._parent.getActualPosition();
                    if (actualPos.x >= pactual.x
                        && actualPos.x + this._size.w <= pactual.x + this._parent.getSize().w
                        && actualPos.y >= pactual.y
                        && actualPos.y + this._size.h <= pactual.y + this._parent.getSize().h) {
                        var pos = { x: actualPos.x, y: actualPos.y };
                        while (parent != null) {
                            pos.x -= parent._position.x;
                            pos.y -= parent._position.y;
                            parent = parent._parent;
                        }

                        this._position.x = pos.x;
                        this._position.y = pos.y;
                    }
                }
            }
        }
        return BaseLine;
    }]);

    app.factory("NodeContainer", ["BaseNode", "$rootScope", function (BaseNode, $rootScope) {
        var NodeContainer = function (position, size, color, parmas) {
            var svg = $rootScope.svg;
            if (color == undefined) {
                color = "transparent";
            }
            if (parmas != undefined) {
                if (parmas.r == undefined) {
                    parmas.r = "7.5";
                }
                if (parmas.dasharray == undefined) {
                    dasharray = "0";
                }
            } else {
                parmas = { r: 7.5, dasharray: 0 };
            }

            var rect = svg.append("rect")
                .attr("rx", parmas.r)
                .attr("ry", parmas.r)
                .attr("fill", color)
                .attr("stroke", "black")
                .attr("stroke-width", "1")
                .attr("cursor", "move")
                .attr("stroke-dasharray", parmas.dasharray);

            BaseNode.apply(this, [rect, position, size]);

            this.children = [];

            this.addChildren = function (node) {
                this.children.push(node);
                node._parent = this;
            }

            this.hide = function () {
                this._domEl.attr("display", "none");
                for (var i = 0; i < this.children.length; i++) {
                    this.children[i].hide();
                }
            }

            this.onUpdateLayout = function () {
                rect.attr("x", this.getActualPosition().x)
                    .attr("y", this.getActualPosition().y)
                    .attr("width", this.getSize().w)
                    .attr("height", this.getSize().h);

                for (var i = 0; i < this.children.length; i++) {
                    this.children[i].updateLayout();
                }
                if (this.logFlag) {
                    worker.postMessage("Create a container:  x:" + this._position.x + ", y:" + this._position.y);
                }
                this.logFlag = false;
            }

            this.hitTest = function (pos) {
                var actualPosition = this.getActualPosition();
                if (pos.x > actualPosition.x
                    && pos.y > actualPosition.y
                    && pos.x < actualPosition.x + this.getSize().w
                    && pos.y < actualPosition.y + this.getSize().h) {
                    return new HitResult(true, actualPosition.x - pos.x, actualPosition.y - pos.y);
                }
                return new HitResult(false, 0, 0);
            }
        }
        return NodeContainer;
    }]);

    app.factory("ProcessContainer", ["NodeContainer", "$rootScope", function (NodeContainer, $rootScope) {
        var ProcessContainer = function (position, size, color, parmas) {
            var svg = $rootScope.svg;
            svg.attr("height", parmas.svgHeight + 200);
            NodeContainer.apply(this, [position, size, color, parmas]);

            this._textRect = svg.append("rect")
                .attr("rx", parmas.r)
                .attr("ry", parmas.r)
                .attr("fill", parmas.color)
                .attr("stroke", "black")
                .attr("stroke-width", "1")
                .attr("cursor", "move")
                .attr("stroke-dasharray", parmas.dasharray)
                .attr("width", this.getSize().w)
                .attr("height", 20)
            this._text = svg.append('text').attr("font-size", "9").attr("fill", "rgb(0,0,127)").text(parmas.text)

            this.onUpdateLayout = function () {
                this._domEl.attr("x", this.getActualPosition().x)
                    .attr("y", this.getActualPosition().y)
                    .attr("width", this.getSize().w)
                    .attr("height", this.getSize().h);

                this._textRect.attr("x", this.getActualPosition().x).attr("y", this.getActualPosition().y).attr("tag", "rect");
                this._text.attr("x", this.getActualPosition().x + this.getSize().w / 2).attr("y", this.getActualPosition().y + 11);

                for (var i = 0; i < this.children.length; i++) {
                    this.children[i].updateLayout();
                }
                if (this.logFlag) {
                    $rootScope.worker.postMessage("Create a Image:  x:" + this._position.x + ", y:" + this._position.x + ", width:" + this._size.w + ", height:" + this._size.h);
                }
                this.logFlag = false;
            };
        }
        return ProcessContainer;
    }]);

    app.directive("svgHtml", function () {
        var temp = {
            restrict: "E",
            template: "<div style='width: 100%' id='svgContainer'></div>",
            controller: function ($scope, Diagram, ProcessContainer, $rootScope,xmlNode2WfElement) {
                var svg = d3.select("#svgContainer")
                       .append("svg")
                       .attr("width", "100%")
                       .attr("height", 1000)
                       .style("border", "none");

                var diagram = new Diagram(svg);
                $rootScope.svg = svg;
                $rootScope.diagram = diagram;

                var worker = new Worker("../worker.js");
                worker.onmessage = function (e) {
                    console.log(e.data.msg);
                }

                worker.onerror = function (error) {
                    console.log(error.filename + "--" + error.message + "--" + error.lineno);
                }
                $rootScope.worker = worker;


                //var url = getQueryString("path");
                $.ajax({
                    url: "../../resource/xml/SVG01.xml",
                    dataType: 'xml',
                    success: function (data) {
                        xmlNode2WfElement(diagram, null, $(data).find("process"), $(data));
                        //var n = new navigation($(data));
                        //n.renderNavigation(diagram, $(data).find("process").attr("width"));
                    }
                });
            }
        };
        return temp;
    })

    app.factory("Link", ["BaseLine", "$rootScope", function (BaseLine, $rootScope) {
        var Link = function (from, to, path) {
            var svg = $rootScope.svg;
            var worker = $rootScope.worker;
            var marker = document.getElementById("markerArrow");
            if (!marker) {
                svg.append('svg:marker')
                .attr('id', 'markerArrow')
                .attr('orient', 'auto')
                .attr('viewBox', '-5 -5 10 10')
                .attr('refX', 3)
                .attr('markerWidth', 7)
                .attr('markerHeight', 7)
                .append('svg:path')
                .attr('d', 'M 0,0 m -5,-5 L 5,0 L -5,5 Z')
                .attr('fill', '#000')
            }

            var padding = 20;
            //"[[142,175],[290,175]]"

            var line = svg.append('path')
                    .style('marker-end', 'url(#markerArrow)')
                    .attr("stroke", "black")
                    .attr("stroke-width", 1.5)
                    .attr("fill", "none");

            BaseLine.apply(this, [line, null, null]);

            this._from = from;
            this._to = to;
            this._from.addLink(this);
            this._to.addLink(this);

            this._position = { x: JSON.parse(path)[0][0], y: JSON.parse(path)[0][1] };

            this.children = [];

            this.addChildren = function (node) {
                this.children.push(node);
                node._parent = this;
            }

            this.updateLayout = function () {
                if (this.logFlag) {
                    worker.postMessage("Create a Line:  path:" + path);
                }
                this.logFlag = false;
                var that = this;
                line.attr("d", function (d) {
                    var pathData = JSON.parse(path);
                    var lineFunction = d3.svg.line()
                        .x(function (d) {
                            that._position = { x: d[0], y: d[1] };
                            return that.getActualPosition(that._position).x;
                        })
                        .y(function (d) {
                            that._position = { x: d[0], y: d[1] };
                            return that.getActualPosition(that._position).y;
                        })
                        .interpolate("linear");
                    return lineFunction(pathData);
                })
                for (var i = 0; i < this.children.length; i++) {
                    this.children[i].updateLayout();
                }
            }

            this.calcPath = function () {
                var f = this._from.getDomEl();
                var t = this._to.getDomEl();
                var point1 = this._from.getCenterPos();
                var point2 = this._to.getCenterPos();
                return " ";
            }

            this.hitTest = function (pos) {
                var point = JSON.parse(path);
                this._position = { x: point[0][0], y: point[0][1] };
                var firstPoint = this.getActualPosition({ x: point[0][0], y: point[0][1] });
                this._position = { x: point[point.length - 1][0], y: point[point.length - 1][1] };
                var lastPoint = this.getActualPosition({ x: point[point.length - 1][0], y: point[point.length - 1][1] });
                if (pos.x > firstPoint.x && pos.x < lastPoint.x && pos.y > lastPoint.y && pos.y < firstPoint.y) {
                    return new HitResult(true, lastPoint.x - pos.x, firstPoint.y - pos.y);
                }
                return new HitResult(false, 0, 0);
            }
        }
        return Link;
    }]);

    app.factory("Text", ["BaseNode", "$rootScope", function (BaseNode, $rootScope) {
        var Text = function (position, size, imageText) {
            var svg = $rootScope.svg;
            var text = svg.append('text')
            .attr("font-size", "9")
            .attr("fill", "rgb(0,0,127)")

            BaseNode.apply(this, [text, position, size]);

            this.onUpdateLayout = function () {
                text.attr("x", this.getActualPosition().x);
                text.attr("y", this.getActualPosition().y);
                text.text(imageText);
                if (this.logFlag) {
                    $rootScope.worker.postMessage("Create a Text:" + imageText);
                }
                this.logFlag = false;
            };
            this.hitTest = function () {
                return new HitResult(false, 0, 0);
            }

            this.getCenterPos = function () {
                var x = this._position.x + (this._size.w) / 2;
                var y = this._position.y + (this._size.h) / 2;
                return { x: x, y: y };
            }
        }
        return Text;
    }])

    app.factory("createSvgDom", ["Link", "Text", function (Link, Text) {
        var createSvgDom = function (type, params) {
            var el = null;
            if (type == "Link") {
                el = new Link(params.from, params.to, params.points);
                if (params.text != undefined) {
                    var p = JSON.parse(params.points);
                    var fx = p[0][0];
                    var lx = p[p.length - 1][0];
                    var text = new Text({ x: -(lx - fx) / 2, y: 20 }, { w: 0, h: 0 }, params.text);
                    el.addChildren(text);
                    el = { parent: el, text: text };
                }
            }
            return el;
        }
        return createSvgDom;
    }])

    app.factory("Image", ["BaseNode", "$rootScope", function (BaseNode, $rootScope) {
        var Image = function (position, size, src, text) {
            var svg = $rootScope.svg;
            var image = svg.append('image')
                        .attr("xlink:href", src)

            this._text = null;
            if (text != undefined && size.h > 16) {
                this._text = svg.append('text')
                            .attr("font-size", "9")
                            .attr("fill", "rgb(0,0,127)")
                                .text(text);
                //new Text({ x: this.getSize().w + 10, y: this.getSize().h + 12 }, { w: 0, h: 0 }, parmas.text);
            }

            BaseNode.apply(this, [image, position, size]);

            this.hide = function () {
                this._domEl.attr("display", "none");
                if (this._text != null) {
                    this._text.attr("display", "none");
                }
            }

            this.onUpdateLayout = function () {
                image.attr("x", this.getActualPosition().x)
                    .attr("y", this.getActualPosition().y)
                    .attr("width", this.getSize().w)
                    .attr("height", this.getSize().h);

                if (this.logFlag) {
                    $rootScope.worker.postMessage("Create a Image:  x:" + this._position.x + ", y:" + this._position.x + ", width:" + this._size.w + ", height:" + this._size.h);
                }
                this.logFlag = false;
                if (this._text != null) {
                    this._text.attr("x", this.getActualPosition().x + 10);
                    this._text.attr("y", this.getActualPosition().y + this.getSize().h + 12);
                }
            };

            this.hitTest = function (pos) {
                var actualPosition = this.getActualPosition();
                if (pos.x > actualPosition.x
                    && pos.y > actualPosition.y
                    && pos.x < actualPosition.x + this.getSize().w
                    && pos.y < actualPosition.y + this.getSize().h) {
                    return new HitResult(true, actualPosition.x - pos.x, actualPosition.y - pos.y);
                }
                return new HitResult(false, 0, 0);
            }

            this.getCenterPos = function () {
                var x = this.getActualPosition().x + (this._size.w) / 2;
                var y = this.getActualPosition().y + (this._size.h) / 2;
                return { x: x, y: y };
            }
        }
        return Image;
    }])

    app.factory("xmlNode2WfElement", ["ProcessContainer", "Link", "createSvgDom", "Image", function (ProcessContainer, Link, createSvgDom, Image) {
        var xmlNode2WfElement = function (wfDiagram, parentElement, xmlNode, xmlElement) {
            var element = null;
            var xmlTagName = $(xmlNode).get(0).tagName.split(':')[1];

            var position = { x: parseInt($(xmlNode).attr("x")), y: parseInt($(xmlNode).attr("y")) };
            var size = { w: parseInt($(xmlNode).attr("width")), h: parseInt($(xmlNode).attr("height")) };

            if (xmlTagName == "process") {
                element = new ProcessContainer(position, size, "white", { r: 5, color: "rgb(255,233,130)", text: $(xmlNode).attr("name"), svgHeight: parseInt($(xmlNode).attr("height")) + 50 });
                processEl = element;
            }
            else if (xmlTagName == "scope") {
                if ($(xmlNode).attr("x") != undefined) {
                    element = new ScopeContainer(position, size, "white", { r: 15, expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "pick") {
                if ($(xmlNode).attr("x") != undefined) {
                    element = new PickContainer(position, size, "white", { r: 15, expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "catch") {
                if ($(xmlNode).attr("x") != undefined) {
                    var catchText = $(xmlNode).attr("faultName");
                    if (catchText == undefined) {
                        catchText = "";
                    } else {
                        catchText = catchText.split(':')[1];
                    }
                    element = new CatchContainer(position, size, "white", { r: 4, text: catchText, color: "transparent", leftImage: imageMap["catchLeftImg"], leftTopImg: imageMap["catchImg"], expand: $(xmlNode).attr("collapse") });
                }
            } else if (xmlTagName == "catchAll") {
                if ($(xmlNode).attr("x") != undefined) {
                    element = new CatchContainer(position, size, "white", { r: 4, text: "Exception", color: "transparent", leftImage: imageMap["catchAllLeftImg"], leftTopImg: imageMap["catchAll"], expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "onMessage") {
                if ($(xmlNode).attr("x") != undefined) {
                    var operation = $(xmlNode).attr("operation");
                    var partnerLink = $(xmlNode).attr("partnerLink");
                    var text = "";
                    if (operation != undefined && partnerLink != undefined) {
                        text = partnerLink + "/" + operation;
                    }
                    element = new OnMessageContainer(position, size, "white", { r: 4, text: text, color: "transparent", leftImage: imageMap["groupStart"], rightImage: imageMap["groupEnd"], expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "compensationHandler") {
                if ($(xmlNode).attr("x") != undefined) {
                    element = new CompensationHandlerContainer(position, size, "white", { r: 15, leftRx: 4, color: "transparent", dasharray: 7, text: "Compensation", expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "onEvent") {
                if ($(xmlNode).attr("x") != undefined) {
                    var operation = $(xmlNode).attr("operation");
                    var partnerLink = $(xmlNode).attr("partnerLink");
                    var text = "";
                    if (operation != undefined && partnerLink != undefined) {
                        text = partnerLink + "/" + operation;
                    }
                    element = new OnEventContainer(position, size, "white", { r: 4, text: text, color: "transparent", leftImage: imageMap["onEventLeftImg"], expand: $(xmlNode).attr("collapse") });
                }
            }
            else if (xmlTagName == "extensionActivity" || xmlTagName == "empty" || xmlTagName == "reply" || xmlTagName == "write" || xmlTagName == "invoke") {
                var tempImg = imageMap[$(xmlNode).attr("type")];
                if (tempImg == undefined) {
                    tempImg = imageMap["groupStart"];
                }
                element = new Image(position, size, tempImg, $(xmlNode).attr("name"));
            }
            else if (xmlTagName == "link") {
                if ($(xmlNode).attr("points") != undefined) {
                    if ($(xmlNode).attr("tibex:label") == undefined) {
                        element = createSvgDom("Link", { from: parentElement, to: parentElement, points: $(xmlNode).attr("points") });
                    }
                    else {
                        element = createSvgDom("Link", { from: parentElement, to: parentElement, points: $(xmlNode).attr("points"), text: $(xmlNode).attr("tibex:label") });
                        wfDiagram.addElement(element.text);
                        element = element.parent;
                    }
                }
            }

            if (element != null) {
                var children = $(xmlNode).children();
                if (children != null) {
                    children.each(function () {
                        xmlNode2WfElement(wfDiagram, element, $(this), xmlElement);
                    })
                }
                if (parentElement != null) {
                    parentElement.addChildren(element);
                    wfDiagram.addElement(element);
                }
                else {
                    wfDiagram.addElement(element);
                }
            }
            else {
                var children = $(xmlNode).children();
                if (children != null) {
                    children.each(function () {
                        xmlNode2WfElement(wfDiagram, parentElement, $(this), xmlElement);
                    })
                }
            }
        }
        return xmlNode2WfElement;
    }])
</script>
